import json
import httpx
from typing import Any
from mcp.server.fastmcp import FastMCP
from dotenv import load_dotenv
import os
import PyPDF2
from docx import Document
import requests
from urllib.parse import urlparse
load_dotenv()
from semantic_index import SemanticIndex

# 初始化 MCP 服务器
mcp = FastMCP("WeatherServer")

# OpenWeather API 配置
OPENWEATHER_API_BASE = os.getenv("OPENWEATHER_API_BASE")
API_KEY = os.getenv("WEATHER_KEY")  # 请替换为你自己的 OpenWeather API Key
USER_AGENT = os.getenv("USER_AGENT")

DOCS_DIR = os.getenv("DOCS_DIR", "./documents")
IDX = SemanticIndex(docs_dir=DOCS_DIR)  # 可换模型名
IDX.ensure_built()  # 启动时构建/加载

def scan_documents(base_path: str, extensions=(".pdf", ".txt", ".docx")) -> list[str]:
    """
    扫描指定路径下的所有文档文件
    """
    file_paths = []
    for root, _, files in os.walk(base_path):
        for file in files:
            if file.lower().endswith(extensions):
                file_paths.append(os.path.join(root, file))
    return file_paths

# 文档处理功能
def read_pdf(file_path: str) -> str:
    """读取 PDF 文件内容"""
    try:
        with open(file_path, 'rb') as file:
            pdf_reader = PyPDF2.PdfReader(file)
            text = ""
            for page in pdf_reader.pages:
                text += page.extract_text() + "\n"
            return text
    except Exception as e:
        return f"读取 PDF 文件失败: {str(e)}"

def read_txt(file_path: str) -> str:
    """读取文本文件内容"""
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            return file.read()
    except Exception as e:
        return f"读取文本文件失败: {str(e)}"

def read_docx(file_path: str) -> str:
    """读取 Word 文档内容"""
    try:
        doc = Document(file_path)
        text = ""
        for paragraph in doc.paragraphs:
            text += paragraph.text + "\n"
        return text
    except Exception as e:
        return f"读取 Word 文档失败: {str(e)}"

def read_document(file_path: str) -> str:
    """根据文件类型读取文档内容"""
    if file_path.endswith('.pdf'):
        return read_pdf(file_path)
    elif file_path.endswith('.txt'):
        return read_txt(file_path)
    elif file_path.endswith('.docx'):
        return read_docx(file_path)
    else:
        return "不支持的文件格式，请使用 PDF、TXT 或 DOCX 格式"


def search_in_content(content: str, query: str) -> str:
    """在文档内容中搜索相关信息"""
    lines = content.split('\n')
    relevant_lines = []

    for line in lines:
        if query.lower() in line.lower():
            relevant_lines.append(line.strip())

    if relevant_lines:
        return f"在文档中找到以下相关信息：\n" + "\n".join(relevant_lines[:10])  # 限制返回结果数量
    else:
        return "在文档中没有找到相关信息"


@mcp.tool()
async def read_and_query_document(file_path: str, question: str) -> str:
    """
    读取文档文件并回答相关问题。支持 PDF、TXT、DOCX 格式。

    Args:
        file_path: 文档文件的路径
        question: 要查询的问题

    Returns:
        文档中的相关内容或答案
    """
    # 读取文档内容
    content = read_document(file_path)

    if content.startswith("读取") and "失败" in content:
        return content

    # 简单的关键词匹配搜索
    if "总结" in question or "概述" in question:
        # 返回前500个字符作为总结
        summary = content[:500] + "..." if len(content) > 500 else content
        return f"文档总结：\n{summary}"
    else:
        # 搜索相关内容
        return search_in_content(content, question)


@mcp.tool()
async def get_document_summary(file_path: str) -> str:
    """
    获取文档的摘要信息

    Args:
        file_path: 文档文件的路径

    Returns:
        文档摘要
    """
    content = read_document(file_path)

    if content.startswith("读取") and "失败" in content:
        return content

    # 返回前300个字符作为摘要
    summary = content[:300] + "..." if len(content) > 300 else content
    return f"文档摘要：\n{summary}"


async def fetch_weather(city: str) -> dict[str, Any] | None:
    print(f"[调用天气工具查询条件 {str}]")
    """
    从 OpenWeather API 获取天气信息。
    :param city: 城市名称（需使用英文，如 Beijing）
    :return: 天气数据字典；若出错返回包含 error 信息的字典
    """
    params = {
        "q": city,
        "appid": API_KEY,
        "units": "metric",
        "lang": "zh_cn"
    }
    headers = {"User-Agent": USER_AGENT}

    async with httpx.AsyncClient() as client:
        try:
            response = await client.get(OPENWEATHER_API_BASE, params=params, headers=headers, timeout=30.0)
            response.raise_for_status()
            weather_data = response.json()
            print(f"返回的字典: {weather_data}")
            return response.json()  # 返回字典类型
        except httpx.HTTPStatusError as e:
            return {"error": f"HTTP 错误: {e.response.status_code}"}
        except Exception as e:
            return {"error": f"请求失败: {str(e)}"}

def format_weather(data: dict[str, Any] | str) -> str:
    """
    将天气数据格式化为易读文本。
    :param data: 天气数据（可以是字典或 JSON 字符串）
    :return: 格式化后的天气信息字符串
    """
    # 如果传入的是字符串，则先转换为字典
    if isinstance(data, str):
        try:
            data = json.loads(data)
        except Exception as e:
            return f"无法解析天气数据: {e}"

    # 如果数据中包含错误信息，直接返回错误提示
    if "error" in data:
        return f"⚠️ {data['error']}"

    # 提取数据时做容错处理
    city = data.get("name", "未知")
    country = data.get("sys", {}).get("country", "未知")
    temp = data.get("main", {}).get("temp", "N/A")
    humidity = data.get("main", {}).get("humidity", "N/A")
    wind_speed = data.get("wind", {}).get("speed", "N/A")
    # weather 可能为空列表，因此用 [0] 前先提供默认字典
    weather_list = data.get("weather", [{}])
    description = weather_list[0].get("description", "未知")

    return (
        f"🌍 {city}, {country}\n"
        f"🌡 温度: {temp}°C\n"
        f"💧 湿度: {humidity}%\n"
        f"🌬 风速: {wind_speed} m/s\n"
        f"🌤 天气: {description}\n"
    )

@mcp.tool()
async def query_weather(city: str) -> str:
    """
    输入指定城市的英文名称，返回今日天气查询结果。
    :param city: 城市名称（需使用英文）
    :return: 格式化后的天气信息
    """
    data = await fetch_weather(city)
    return format_weather(data)
@mcp.tool()
async def semantic_read(question: str, top_k: int = 5) -> str:
    """
    基于语义检索在 documents/ 里找相关片段，返回可读上下文。
    """
    hits = IDX.search(question, top_k=top_k)
    return IDX.format_hits(hits)

if __name__ == "__main__":
    # 以标准 I/O 方式运行 MCP 服务器
    mcp.run(transport='stdio')